#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##-- G02 -- S01 ------------------------------------------------------------##
__all__ = []

from .. import formlib as layout
from .. import pilelib as stack
from ..gamelib import info as gi, game, state
from ..hint import CautiousDefaultHint
from ..packlib import info as cs

GT, SL = gi.GT, gi.SL
Wrap = stack.StackWrapper


class Reserve(stack.OpenStack):

    def cardFlips(self):
        """
        cardFlips() -> bool

        Check pile flip top card. Overide prevent flipping.

        :return: pile flips top card?
        :rtype: boolean
        """
        return False


class HeadsAndTails(game.Game):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 16 over 2 row. Init deal 1 card. Build in rank by same suit. N up
      and S down. Play top. Gap deal 1 card from closest neighbor _reserve_.
      Base any.

    _reserve_
      Pile 8 between _row_. Init deal 11 close card. Build none. Play none.

    _foundation_
      Pile 8 over 2 col E W. Build in rank by same suit. E up and W down. Play
      top.

    seealso::
        http://en.wikipedia.org/wiki/Heads_And_Tails
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.SS_Foundation,
      stack.SS_Foundation (base_rank=KING, dir=-1)
    :cvar Stack _row_: stack.SS_RowStack (dir=1, max_move=1, max_accept=1),
      stack.SS_RowStack (max_move=1, max_accept=1),
    :cvar Stack _reserve_: Reserve
    :cvar Hint _hint_: hint.CautiousDefaultHint
    """
    __info__ = dict(id=307, name='Heads and Tails', game_type=GT.TWO_DECK,
                    decks=2, redeals=0, skill_level=SL.BALANCED,
                    version='0.80fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = stack.InitialDealTalon
    _foundations_ = (stack.SS_Foundation,
                    Wrap(stack.SS_Foundation, base_rank=cs.KING,
                                 dir=-1),)
    _rows_ = (Wrap(stack.SS_RowStack, dir=1, max_move=1,
                           max_accept=1),
              Wrap(stack.SS_RowStack, max_move=1, max_accept=1),)
    _reserve_ = Reserve
    _hint_ = CautiousDefaultHint

    def _create_game(self, rows=16, reserves=8, playcards=8, **kw):
        l, s = layout.Layout(self), self.s
        dy = l._set_stack_height(playcards, height=l.YS)
        self.table_size = (l.XM + (max(max(rows), reserves) + 2) * l.XS,
                           l.YM + l.YS + 2 * dy)
        x, y = self.width - l.XS, self.height - l.YS
        s['talon'] = self._talon_(x, y, game=self)
        dx, y = l.XM + l.XS, l.YM
        for _row_ in self._rows_:  # Vert
            x = dx
            for i in range(rows / 2):  # Horz
                s['rows'].append(_row_(x, y, game=self))
                x += l.XS
            y += l.YS + dy
        x, y = dx, l.YM + dy
        for i in range(reserves):  # Horz
            s['reserves'].append(self._reserve_(x, y, game=self))
            l.set_ncards_text(s['reserves'][i], 'n')
            x += l.XS
        dx, y = self.width - l.XS, l.YM
        for _foundation_ in self._foundations_:  # Vert
            x = l.XM
            for suit in l.SUIT:  # Horz
                s['foundations'].append(_foundation_(x, y, game=self, suit=suit))
                x += dx
            y += l.YS
        l.defaultStackGroups()
        return l

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[reserves] 11 ea dn.
          - s[rows] 1 ea.

        .. \_start([]) -> None
        """
        for i in range(11):
            self.s['talon'].dealRow(rows=self.s['reserves'], frames=0,
                                    flip=False)
        self.s['talon'].dealRow()

    @state.move_state('fill')
    def _auto_fill(self, stack):
        """
        Fill stack if _row_ when gap from closest neighbor _reserve_.

        *Parameters*:
          stack : Stack
            pile just played
        """
        if stack in self.s['rows'] and not stack.cards:
            reserves = self.s['reserves']
            si = self.s['rows'].index(stack) % 8
            from_stack = None
            if reserves[si].cards:
                from_stack = reserves[si]
            else:
                for i in range(1, 8):
                    n = si + i
                    if n < 8 and reserves[n].cards:
                        from_stack = reserves[n]
                        break
                    n = si - i
                    if n >= 0 and reserves[n].cards:
                        from_stack = reserves[n]
                        break
            if not from_stack:
                return
            self.fill(from_stack, stack)


class Barrier(game.Game):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 10 horz S _reserve_. Init deal 2 open card. Build down in rank by
      alt color. Play seq.

    _reserve_
      Pile 4 horz offset above 8 horz N. Init deal N 19 card and S 1 card.
      Build none. Play N none and S top.

    _foundation_
      Pile 8 horz S. Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Stack _reserve_: stack.OpenStack, Reserve
    """
    __info__ = dict(id=708, name='Barrier', game_type=(GT.TWO_DECK |
                    GT.ORIGINAL), decks=2, redeals=0, skill_level=SL.BALANCED,
                    version='1.00fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = stack.InitialDealTalon
    _foundation_ = stack.SS_Foundation
    _row_ = stack.AC_RowStack
    _reserve_ = (stack.OpenStack, Reserve,)

    def _create_game(self, rows=10, reserves=8, playcards=12):
        # TODO fix reserves to one reserve key only
        l, s = layout.Layout(self), self.s
        max_rows = max(8, rows, reserves)
        self.table_size = (l.XM + max_rows * l.XS,
                        l.YM + 3 * l.YS + l._get_stack_height(playcards, l.YS),)
        center = lambda p: l.XM + (max_rows - p) * l.XS / 2
        x, y = center(reserves) + l.XS / 2, l.YM
        s['reserves2'] = []
        for i in range(reserves / 2):  # Horz
            s['reserves2'].append(self._reserve_[0](x, y, game=self))
            l.set_ncards_text(s['reserves2'][i], 'ne')
            x += 2 * l.XS
        x = center(reserves)
        y += l.YS
        for i in range(reserves):  # Horz
            s['reserves'].append(self._reserve_[1](x, y, game=self))
            x += l.XS
        x = center(rows)
        y += l.YS
        for i in range(rows):  # Horz
            s['rows'].append(self._row_(x, y, game=self))
            x += l.XS
        x, y = center(l.NSUITS), self.height - l.YS
        for suit in l.SUITS:  # Horz
            s['foundations'].append(self._foundation_(x, y, game=self,
                                                   suit=suit))
            x += l.XS
        x, y = l.XM, self.height - l.YS
        s['talon'] = self._talon_(x, y, game=self)
        l.defaultStackGroups()
        return l

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[reserves] 1 ea
          - s[rows] 2 ea.
          - s[reserves] remain dn.

        .. \_start([]) -> None
        """
        self.s['talon'].dealRow(rows=self.s['reserves'], frames=0)
        for i in range(2):
            self.s['talon'].dealRow()
        while s['talon'].cards:
            self.s['talon'].dealRowAvail(rows=self.s['reserves2'], frames=0,
                                         flip=False)

    @state.move_state('fill')
    def _auto_fill(self, stack):
        """
        Fill stack if _reserve_[0] when gap from neighbor _reserve_[1].

        *Parameters*:
          stack : Stack
            pile just played
        """
        if stack in self.s['reserves'] and not stack.cards:
            si = self.s['reserves'].index(stack)
            from_stack = self.s['reserves2'][si / 2]
            if not from_stack.cards:
                return
            self.fill(from_stack, stack)

PROVIDES = [HeadsAndTails, Barrier]